package scfg.utils;

import java.io.*;
import java.util.*;
import java.util.Map.Entry;

import scfg.Grammar;
import scfg.output.Display;
import scfg.output.RNAFormattedFile;

public class CtConstraintsGenerator {
	
	public static boolean enableExtraConstraints = false;
	
	public static boolean checkConnonicalPair(String pair) {
		return pair.toUpperCase().matches("(AU|UA|GC|CG|GU|UG)");
	}
	
	public static String processFile(String filename, String outputName) {
		if (filename != null && outputName != null)
			return processFile(new File(filename), new File(outputName));
		if (filename != null)
			return processFile(new File(filename));
		// TODO:
		return null;
	}
	
	public static String processFile(File f) {
		return processFile(f, null);
	}
	
	public static String processFile(File f, File outputFile) {
		if (f == null || !f.exists() || !f.isFile()){
			// TODO: 
//			System.err.println("ARGS: " + f.getAbsolutePath());
			return null;
		} else if (!f.getName().contains(".nopct") && !f.getName().contains(".ct")) {
			// TODO: 
//			if(!f.getName().contains(".cnstr"))
//				System.err.println("NAME: " + f.getAbsolutePath());
			return null;
		}
		RNAFormattedFile rnaff = StructureAggregator.convertCtFile(f, new RNAFormattedFile());
		if (rnaff != null && rnaff.get("seq") != null && rnaff.get("nat") != null) {
			StringBuilder sb = new StringBuilder();
			Map<String, Integer> constraints = new HashMap<String, Integer>();
			String seq = rnaff.get("seq");
			String str = rnaff.get("nat");
//			String seq = "CCCCAAAAGGGG";
//			String str = "(((.(...))))";
			int[] pairs = Grammar.getPairsArraySt(str);
			for(int i=0;i<seq.length();i++) {
				switch (str.charAt(i)) {
				case '(' :
					int iVal = i + 1;
					int jVal = pairs[i] + 1;
					if (checkConnonicalPair((seq.charAt(i)+"")+(seq.charAt(pairs[i])+""))){
						String key = "F " + iVal + " " + jVal;
						if (constraints.get(key) == null || constraints.get(key) < 1)
							constraints.put(key, 1);
//						sb.append("F ").append(iVal).append(" ").append(jVal);
					}
					else {
//						sb.append("P ").append(iVal).append(" 0 1\n");
						String key = "P " + iVal + " 0";
						if (constraints.get(key) == null || constraints.get(key) < 1)
							constraints.put(key, 1);
//						sb.append("P ").append(jVal).append(" 0 1\n");
						key = "P " + jVal + " 0";
						if (constraints.get(key) == null || constraints.get(key) < 1)
							constraints.put(key, 1);
						if (enableExtraConstraints) {
							int jp = jVal - 1;
							for (int ip=1;ip<iVal;ip++) {
								int min = Math.min(iVal-ip, jVal-iVal-1);
//								sb.append("P ").append(ip).append(" ").append(jp).append(" ").append(min).append("\n");
								key = "P " + ip + " " + jVal;
								if (constraints.get(key) == null || constraints.get(key) < min)
									constraints.put(key, min);
							}
							jp = seq.length();
							for (int ip=iVal+1;ip<jVal;ip++) {
								int min = Math.min(jVal-ip, jp-jVal+1);
//								sb.append("P ").append(ip).append(" ").append(jp).append(" ").append(min).append("\n");
								key = "P " + iVal + " " + jVal;
								if (constraints.get(key) == null || constraints.get(key) < min)
									constraints.put(key, min);
							}
						}
					}
					break;
				case '.' :
					break;
				case ')':
					break;
				default :
				}
			}
			if (outputFile != null) {
				File outputDir = new File(outputFile.getAbsolutePath().replace(outputFile.getName(), ""));
				outputDir.mkdirs();
				String constraintFileName = outputFile.getAbsolutePath().replace(".nopct", ".cnstr");
				if (enableExtraConstraints)
					constraintFileName += "X";
				Display fileout = new Display(constraintFileName, null, false);
				for (Entry<String, Integer> me : constraints.entrySet())
					sb.append(me.getKey()).append(" ").append(me.getValue().toString()).append("\n");
				fileout.outC(sb.toString());
				fileout.finalizeDisplay();
			}
			return sb.toString();
		} // else
//			System.err.println("NULL: " + f.getAbsolutePath());
		return null;
	}
	
	public static void processDir(String filename, String destination) {
		processDir(new File(filename), destination);
	}
	
	public static void processDir(File base, String destination) {
		if (base == null || !base.exists() || !base.isDirectory()){
			// TODO:
			return;
		}
		File[] files = base.listFiles();
		Queue<File> dirs = new LinkedList<File>();
		for (File f : files) {
			if (f.isDirectory())
				dirs.offer(f);
			else
				processFile(f, new File(destination + "/" + f.getName()));
		}
		while (!dirs.isEmpty()) {
			File f = dirs.poll();
			processDir(f, destination + "/" + f.getName());
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String filename = "/home/david/Documents/RNA/ct_files/";
		String destination = "/home/david/Documents/RNA/ct_files/con/";
		enableExtraConstraints = true;
		processDir(filename, destination);
		enableExtraConstraints = false;
		processDir(filename, destination);
	}

}
